# -*- coding: utf-8 -*-
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#
#  Author: Mauro Soria

from optparse import OptionParser, OptionGroup

from lib.core.settings import (
    AUTHENTICATION_TYPES,
    SCRIPT_PATH,
    VERSION,
)
from lib.utils.file import FileUtils


def parse_arguments():
    usage = "Usage: %prog [-u|--url] target [-e|--extensions] extensions [options]"
    parser = OptionParser(usage, version=f"dirsearch v{VERSION}")

    # Mandatory arguments
    mandatory = OptionGroup(parser, "Mandatory")
    mandatory.add_option(
        "-u",
        "--url",
        action="append",
        dest="urls",
        metavar="URL",
        help="目标URL，可以使用多个标志",
    )
    mandatory.add_option(
        "-l",
        "--url-file",
        action="store",
        dest="url_file",
        metavar="PATH",
        help="URL列表文件",
    )
    mandatory.add_option(
        "--stdin", action="store_true", dest="stdin_urls", help="从STDIN读取URL"
    )
    mandatory.add_option("--cidr", action="store", dest="cidr", help="目标CIDR")
    mandatory.add_option(
        "--raw",
        action="store",
        dest="raw_file",
        metavar="PATH",
        help="从文件加载原始HTTP请求（使用“--scheme”标志设置方案）",
    )
    mandatory.add_option(
        "-s", "--session", action="store", dest="session_file", help="会话文件"
    )
    mandatory.add_option(
        "--config",
        action="store",
        dest="config",
        metavar="PATH",
        help="配置文件的完整路径，例如参见“config.ini”（默认值：config.ini）",
        default=FileUtils.build_path(SCRIPT_PATH, "config.ini"),
    )

    # Dictionary Settings
    dictionary = OptionGroup(parser, "Dictionary Settings")
    dictionary.add_option(
        "-w",
        "--wordlists",
        action="store",
        dest="wordlists",
        help="自定义单词表（用逗号分隔）",
    )
    dictionary.add_option(
        "-e",
        "--extensions",
        action="store",
        dest="extensions",
        help="用逗号分隔的扩展列表（例如php、asp）",
    )
    dictionary.add_option(
        "-f",
        "--force-extensions",
        action="store_true",
        dest="force_extensions",
        help="在每个单词表条目的末尾添加扩展名。默认情况下，dirsearch仅将%EXT%关键字替换为扩展名",
    )
    dictionary.add_option(
        "-O",
        "--overwrite-extensions",
        action="store_true",
        dest="overwrite_extensions",
        help="用您的扩展名覆盖单词表中的其他扩展名（通过`-e`选择）",
    )
    dictionary.add_option(
        "--exclude-extensions",
        action="store",
        dest="exclude_extensions",
        metavar="EXTENSIONS",
        help="排除以逗号分隔的扩展名列表（例如asp、jsp）",
    )
    dictionary.add_option(
        "--remove-extensions",
        action="store_true",
        dest="remove_extensions",
        help="删除所有路径中的扩展名（例如admin.php->admin）",
    )
    dictionary.add_option(
        "--prefixes",
        action="store",
        dest="prefixes",
        help="为所有单词表条目添加自定义前缀（用逗号分隔）",
    )
    dictionary.add_option(
        "--suffixes",
        action="store",
        dest="suffixes",
        help="为所有单词表条目添加自定义后缀，忽略目录（用逗号分隔）",
    )
    dictionary.add_option(
        "-U",
        "--uppercase",
        action="store_true",
        dest="uppercase",
        help="大写单词表",
    )
    dictionary.add_option(
        "-L",
        "--lowercase",
        action="store_true",
        dest="lowercase",
        help="小写单词表",
    )
    dictionary.add_option(
        "-C",
        "--capital",
        action="store_true",
        dest="capitalization",
        help="大写单词表",
    )

    # Optional Settings
    general = OptionGroup(parser, "General Settings")
    general.add_option(
        "-t",
        "--threads",
        action="store",
        type="int",
        dest="thread_count",
        metavar="THREADS",
        help="线程数",
    )
    general.add_option(
        "-r",
        "--recursive",
        action="store_true",
        dest="recursive",
        help="递归用力",
    )
    general.add_option(
        "--deep-recursive",
        action="store_true",
        dest="deep_recursive",
        help="对每个目录深度执行递归扫描（例如api/users->api/）",
    )
    general.add_option(
        "--force-recursive",
        action="store_true",
        dest="force_recursive",
        help="对每个找到的路径进行递归暴力破解，而不仅仅是目录",
    )
    general.add_option(
        "-R",
        "--max-recursion-depth",
        action="store",
        type="int",
        dest="recursion_depth",
        metavar="DEPTH",
        help="最大递归深度",
    )
    general.add_option(
        "--recursion-status",
        action="store",
        dest="recursion_status_codes",
        metavar="CODES",
        help="执行递归扫描的有效状态代码，支持范围（用逗号分隔）",
    )
    general.add_option(
        "--subdirs",
        action="store",
        dest="subdirs",
        metavar="SUBDIRS",
        help="扫描给定URL的子目录（用逗号分隔）",
    )
    general.add_option(
        "--exclude-subdirs",
        action="store",
        dest="exclude_subdirs",
        metavar="SUBDIRS",
        help="在递归扫描期间排除以下子目录（用逗号分隔）",
    )
    general.add_option(
        "-i",
        "--include-status",
        action="store",
        dest="include_status_codes",
        metavar="CODES",
        help="包括状态代码，用逗号分隔，支持范围（例如200300-399）",
    )
    general.add_option(
        "-x",
        "--exclude-status",
        action="store",
        dest="exclude_status_codes",
        metavar="CODES",
        help="排除状态代码，用逗号分隔，支持范围（例如301500-599）",
    )
    general.add_option(
        "--exclude-sizes",
        action="store",
        dest="exclude_sizes",
        metavar="SIZES",
        help="按大小排除响应，用逗号分隔（例如0B、4KB）",
    )
    general.add_option(
        "--exclude-text",
        action="append",
        dest="exclude_texts",
        metavar="TEXTS",
        help="按文本排除响应，可以使用多个标志",
    )
    general.add_option(
        "--exclude-regex",
        action="store",
        dest="exclude_regex",
        metavar="REGEX",
        help="通过正则表达式排除响应",
    )
    general.add_option(
        "--exclude-redirect",
        action="store",
        dest="exclude_redirect",
        metavar="STRING",
        help="如果此正则表达式（或文本）与重定向URL（例如“/index.html”）匹配，则排除响应",
    )
    general.add_option(
        "--exclude-response",
        action="store",
        dest="exclude_response",
        metavar="PATH",
        help="排除与此页面的响应类似的响应，路径作为输入（例如404.html）",
    )
    general.add_option(
        "--skip-on-status",
        action="store",
        dest="skip_on_status",
        metavar="CODES",
        help="只要碰到这些状态代码之一，就跳过目标，用逗号分隔，支持范围",
    )
    general.add_option(
        "--min-response-size",
        action="store",
        type="int",
        dest="minimum_response_size",
        help="最小响应长度",
        metavar="LENGTH",
        default=0,
    )
    general.add_option(
        "--max-response-size",
        action="store",
        type="int",
        dest="maximum_response_size",
        help="最大响应长度",
        metavar="LENGTH",
        default=0,
    )
    general.add_option(
        "--max-time",
        action="store",
        type="int",
        dest="max_time",
        metavar="SECONDS",
        help="扫描的最大运行时间",
    )
    general.add_option(
        "--exit-on-error",
        action="store_true",
        dest="exit_on_error",
        help="发生错误时退出",
    )

    # Request Settings
    request = OptionGroup(parser, "Request Settings")
    request.add_option(
        "-m",
        "--http-method",
        action="store",
        dest="http_method",
        metavar="METHOD",
        help="HTTP方法（默认：GET）",
    )
    request.add_option(
        "-d", "--data", action="store", dest="data", help="HTTP请求数据"
    )
    request.add_option(
        "--data-file",
        action="store",
        dest="data_file",
        metavar="PATH",
        help="File contains HTTP请求数据"
    )
    request.add_option(
        "-H",
        "--header",
        action="append",
        dest="headers",
        help="HTTP请求头，可以使用多个标志",
    )
    request.add_option(
        "--header-file",
        dest="header_file",
        metavar="PATH",
        help="文件包含HTTP请求标头",
    )
    request.add_option(
        "-F",
        "--follow-redirects",
        action="store_true",
        dest="follow_redirects",
        help="遵循HTTP重定向",
    )
    request.add_option(
        "--random-agent",
        action="store_true",
        dest="random_agents",
        help="为每个请求随机选择一个用户代理",
    )
    request.add_option(
        "--auth",
        action="store",
        dest="auth",
        metavar="CREDENTIAL",
        help="身份验证凭证（例如用户：密码或承载令牌）",
    )
    request.add_option(
        "--auth-type",
        action="store",
        dest="auth_type",
        metavar="TYPE",
        help=f"Authentication type ({', '.join(AUTHENTICATION_TYPES)})",
    )
    request.add_option(
        "--cert-file",
        action="store",
        dest="cert_file",
        metavar="PATH",
        help="文件包含客户端证书",
    )
    request.add_option(
        "--key-file",
        action="store",
        dest="key_file",
        metavar="PATH",
        help="文件包含客户端证书 private key (unencrypted)",
    )
    request.add_option("--user-agent", action="store", dest="user_agent")
    request.add_option("--cookie", action="store", dest="cookie")

    # Connection Settings
    connection = OptionGroup(parser, "Connection Settings")
    connection.add_option(
        "--timeout",
        action="store",
        type="float",
        dest="timeout",
        help="连接超时",
    )
    connection.add_option(
        "--delay",
        action="store",
        type="float",
        dest="delay",
        help="请求之间的延迟",
    )
    connection.add_option(
        "--proxy",
        action="append",
        dest="proxies",
        metavar="PROXY",
        help="代理URL（HTTP/SOCKS），可以使用多个标志",
    )
    connection.add_option(
        "--proxy-file",
        action="store",
        dest="proxy_file",
        metavar="PATH",
        help="文件包含代理服务器",
    )
    connection.add_option(
        "--proxy-auth",
        action="store",
        dest="proxy_auth",
        metavar="CREDENTIAL",
        help="代理身份验证凭据",
    )
    connection.add_option(
        "--replay-proxy",
        action="store",
        dest="replay_proxy",
        metavar="PROXY",
        help="使用找到的路径重播的代理",
    )
    connection.add_option(
        "--tor", action="store_true", dest="tor", help="使用Tor网络作为代理"
    )
    connection.add_option(
        "--scheme",
        action="store",
        dest="scheme",
        metavar="SCHEME",
        help="原始请求的方案，或者URL中没有方案（默认：自动检测）",
    )
    connection.add_option(
        "--max-rate",
        action="store",
        type="int",
        dest="max_rate",
        metavar="RATE",
        help="每秒最大请求数",
    )
    connection.add_option(
        "--retries",
        action="store",
        type="int",
        dest="max_retries",
        metavar="RETRIES",
        help="失败请求的重试次数",
    )
    connection.add_option("--ip", action="store", dest="ip", help="服务器IP地址")

    # Advanced Settings
    advanced = OptionGroup(parser, "Advanced Settings")
    advanced.add_option(
        "--crawl",
        action="store_true",
        dest="crawl",
        help="在响应中爬行新路径"
    )

    # View Settings
    view = OptionGroup(parser, "View Settings")
    view.add_option(
        "--full-url",
        action="store_true",
        dest="full_url",
        help="输出中的完整URL（在安静模式下自动启用）",
    )
    view.add_option(
        "--redirects-history",
        action="store_true",
        dest="redirects_history",
        help="显示重定向历史记录",
    )
    view.add_option(
        "--no-color", action="store_false", dest="color", help="无彩色输出"
    )
    view.add_option(
        "-q", "--quiet-mode", action="store_true", dest="quiet", help="静音模式"
    )

    # Output Settings
    output = OptionGroup(parser, "Output Settings")
    output.add_option(
        "-o",
        "--output",
        action="store",
        dest="output_file",
        metavar="PATH",
        help="输出文件",
    )
    output.add_option(
        "--format",
        action="store",
        dest="output_format",
        metavar="FORMAT",
        help="报告格式（可用：简单、纯、json、xml、md、csv、html、sqlite）",
    )
    output.add_option(
        "--log", action="store", dest="log_file", metavar="PATH", help="日志文件"
    )

    parser.add_option_group(mandatory)
    parser.add_option_group(dictionary)
    parser.add_option_group(general)
    parser.add_option_group(request)
    parser.add_option_group(connection)
    parser.add_option_group(advanced)
    parser.add_option_group(view)
    parser.add_option_group(output)
    options, _ = parser.parse_args()

    return options
